#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAXINT 0x3F3F3F3F

struct G_edge {
	int a;
	int b;
	int cost;
};

bool operator < (G_edge lhs, G_edge rhs) {
	return (lhs.cost < rhs.cost);
}

int N;
int Q;
int E;
int G[102][102];
G_edge EDGES[102];
int FL[102];

bool input_vis[102][102];

void input() {
	memset(G, 0x3F, sizeof(G));
	for (int i=1; i<=N; i++) {
		for (int j=1; j<=N; j++) {
			cin >> G[i][j];
		}
	}
	for (int i=1; i<=N; i++) {
		FL[i] = i;
	}
	cin >> Q;
	for (int i=1; i<=Q; i++) {
		int a, b;
		cin >> a >> b;
		int fla = FL[a];
		int flb = FL[b];
		for (int j=1; j<=N; j++) {
			if (FL[j] == flb) {
				FL[j] = fla;
			}
		}
	}
	E=0;
	memset(input_vis, 0, sizeof(input_vis));
	for (int i=1; i<=N; i++) {
		for (int j=1; j<=N; j++) {
			if (i==j) continue;
			if (FL[i] == FL[j]) continue;
			if (G[i][j]<MAXINT && !input_vis[i][j]) {
				input_vis[i][j] = true;
				input_vis[j][i] = true;
				EDGES[E].a = i;
				EDGES[E].b = j;
				EDGES[E].cost = G[i][j];
				E++;
			}
		}
	}
}

int Kruskal() {
	int route=0;
	sort(EDGES, EDGES+E);
	for (int i=0; i<E; i++) {
		int a=EDGES[i].a;
		int b=EDGES[i].b;
		if (FL[a] != FL[b]) {
			for (int j=1; j<=N; j++) {
				if (FL[j] == FL[b]) {
					FL[j] = FL[a];
				}
			}
			route += EDGES[i].cost;
		}
	}
	return route;
}

int main() {
	while ((cin >> N)) {
		input();
		int min = Kruskal();
		cout << min << endl;
	}
	return 0;
}
